import { chromium, Browser, Page } from 'playwright'
import pixelmatch from 'pixelmatch'
import { PNG } from 'pngjs'
import fs from 'fs'
import path from 'path'

/**
 * 视觉相似度对比服务
 * 使用Playwright截图和pixelmatch进行图像对比
 */
export class VisualComparisonService {
  private browser: Browser | null = null
  private page: Page | null = null

  /**
   * 初始化浏览器
   */
  async init(): Promise<void> {
    try {
      this.browser = await chromium.launch({
        headless: true,
        args: ['--no-sandbox', '--disable-setuid-sandbox']
      })
      this.page = await this.browser.newPage()
      await this.page.setViewportSize({ width: 1200, height: 800 })
    } catch (error) {
      console.error('初始化浏览器失败:', error)
      throw error
    }
  }

  /**
   * 关闭浏览器
   */
  async close(): Promise<void> {
    if (this.page) {
      await this.page.close()
      this.page = null
    }
    if (this.browser) {
      await this.browser.close()
      this.browser = null
    }
  }

  /**
   * 截取HTML代码的渲染截图
   * @param htmlContent HTML代码内容
   * @returns 截图的Buffer
   */
  async captureHTMLScreenshot(htmlContent: string): Promise<Buffer> {
    if (!this.page) {
      throw new Error('浏览器未初始化，请先调用init()方法')
    }

    try {
      // 设置HTML内容
      await this.page.setContent(htmlContent, {
        waitUntil: 'networkidle',
        timeout: 10000
      })

      // 等待页面完全加载
      await this.page.waitForTimeout(1000)

      // 截图
      const screenshot = await this.page.screenshot({
        type: 'png',
        fullPage: true,
        animations: 'disabled'
      })

      return screenshot
    } catch (error) {
      console.error('截图失败:', error)
      throw error
    }
  }

  /**
   * 对比两张图片的相似度
   * @param img1Buffer 第一张图片的Buffer
   * @param img2Buffer 第二张图片的Buffer
   * @returns 相似度分数 (0-100)
   */
  async compareImages(img1Buffer: Buffer, img2Buffer: Buffer): Promise<{
    similarity: number
    diffPixels: number
    totalPixels: number
    diffPercentage: number
  }> {
    try {
      const img1 = PNG.sync.read(img1Buffer)
      const img2 = PNG.sync.read(img2Buffer)

      // 确保两张图片尺寸一致
      const width = Math.min(img1.width, img2.width)
      const height = Math.min(img1.height, img2.height)

      // 创建差异图像
      const diff = new PNG({ width, height })

      // 进行像素对比
      const diffPixels = pixelmatch(
        img1.data,
        img2.data,
        diff.data,
        width,
        height,
        {
          threshold: 0.1, // 像素差异阈值
          alpha: 0.1,     // 透明度权重
          antialiasing: true
        }
      )

      const totalPixels = width * height
      const diffPercentage = (diffPixels / totalPixels) * 100
      const similarity = Math.max(0, 100 - diffPercentage)

      return {
        similarity: Math.round(similarity * 100) / 100,
        diffPixels,
        totalPixels,
        diffPercentage: Math.round(diffPercentage * 100) / 100
      }
    } catch (error) {
      console.error('图像对比失败:', error)
      throw error
    }
  }

  /**
   * 从文件加载标准答案图片
   * @param imagePath 图片文件路径
   * @returns 图片Buffer
   */
  async loadReferenceImage(imagePath: string): Promise<Buffer> {
    try {
      const fullPath = path.resolve(imagePath)
      if (!fs.existsSync(fullPath)) {
        throw new Error(`标准答案图片不存在: ${fullPath}`)
      }
      return fs.readFileSync(fullPath)
    } catch (error) {
      console.error('加载标准答案图片失败:', error)
      throw error
    }
  }

  /**
   * 保存截图到文件（用于调试）
   * @param buffer 图片Buffer
   * @param filename 文件名
   */
  async saveScreenshot(buffer: Buffer, filename: string): Promise<void> {
    try {
      const screenshotsDir = path.join(process.cwd(), 'screenshots')
      if (!fs.existsSync(screenshotsDir)) {
        fs.mkdirSync(screenshotsDir, { recursive: true })
      }
      const filePath = path.join(screenshotsDir, filename)
      fs.writeFileSync(filePath, buffer)
      console.log(`截图已保存: ${filePath}`)
    } catch (error) {
      console.error('保存截图失败:', error)
    }
  }
}

/**
 * 获取题目对应的标准答案图片路径
 * @param assignmentId 题目ID
 * @returns 标准答案图片路径
 */
export function getReferenceImagePath(assignmentId: number): string {
  return path.join(process.cwd(), 'public', 'reference-images', `assignment-${assignmentId}.png`)
}

/**
 * 计算视觉相似度分数
 * @param htmlContent HTML代码内容
 * @param assignmentId 题目ID
 * @returns 视觉相似度分数和详细信息
 */
export async function calculateVisualSimilarity(
  htmlContent: string,
  assignmentId: number
): Promise<{
  score: number
  similarity: number
  feedback: string
  details?: {
    diffPixels: number
    totalPixels: number
    diffPercentage: number
  }
}> {
  const visualService = new VisualComparisonService()
  
  try {
    await visualService.init()
    
    // 截取用户代码的渲染图片
    const userScreenshot = await visualService.captureHTMLScreenshot(htmlContent)
    
    // 获取标准答案图片路径
    const referencePath = getReferenceImagePath(assignmentId)
    
    // 检查标准答案图片是否存在
    if (!fs.existsSync(referencePath)) {
      console.warn(`标准答案图片不存在: ${referencePath}`)
      return {
        score: 15, // 给予基础分数
        similarity: 0,
        feedback: '暂无标准答案图片进行对比，基于代码结构评分'
      }
    }
    
    // 加载标准答案图片
    const referenceImage = await visualService.loadReferenceImage(referencePath)
    
    // 进行图像对比
    const comparison = await visualService.compareImages(userScreenshot, referenceImage)
    
    // 计算分数 (相似度转换为30分制)
    const score = Math.round((comparison.similarity / 100) * 30)
    
    // 生成反馈
    let feedback = ''
    if (comparison.similarity >= 90) {
      feedback = '视觉效果优秀，与标准答案高度相似'
    } else if (comparison.similarity >= 75) {
      feedback = '视觉效果良好，与标准答案较为相似'
    } else if (comparison.similarity >= 60) {
      feedback = '视觉效果一般，建议优化布局和样式'
    } else if (comparison.similarity >= 40) {
      feedback = '视觉效果较差，需要大幅改进'
    } else {
      feedback = '视觉效果与标准答案差异较大，请重新设计'
    }
    
    // 保存截图用于调试（可选）
    if (process.env.NODE_ENV === 'development') {
      await visualService.saveScreenshot(
        userScreenshot,
        `user-assignment-${assignmentId}-${Date.now()}.png`
      )
    }
    
    return {
      score,
      similarity: comparison.similarity,
      feedback,
      details: {
        diffPixels: comparison.diffPixels,
        totalPixels: comparison.totalPixels,
        diffPercentage: comparison.diffPercentage
      }
    }
    
  } catch (error) {
    console.error('视觉相似度计算失败:', error)
    return {
      score: 10, // 出错时给予基础分数
      similarity: 0,
      feedback: '视觉对比服务暂时不可用，基于代码结构评分'
    }
  } finally {
    await visualService.close()
  }
}